/**
 * Copyright (C) 2013 SHANGHAI VOLKSWAGEN, All rights reserved.
 * License version 1.0, a copy of which has been included with this.
 *
 * @File name：com.market.test.server.service.impl.UserWrapBatchService
 * @Create on：2024/3/8
 * @Author：liuchang
 */
package com.market.test.server.service.impl;

import com.market.test.common.domain.User;
import com.market.test.server.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Map;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.*;

/**
 * <p>ClassName：UserWrapBatchService</p >
 * <p>Description：</p >
 * <p>Author：liuchang</p >
 * <p>Date：2024/3/8</p >
 */
@Service
public class UserWrapBatchService {
    @Resource
    private UserService userService;


    //最大任务数
    public static int MAX_TASK_NUM=100;




    public class  Request{

        // 请求id  唯一
        String requestId;

        //参数
        Integer userId;
        //TODO  Java 8的CompletableFuture 并没有timeout 机制
        CompletableFuture<User> completableFuture;





        public String getRequestId() {
            return requestId;
        }

        public void setRequestId(String requestId) {
            this.requestId = requestId;
        }

        public Integer getUserId() {
            return userId;
        }

        public void setUserId(Integer userId) {
            this.userId = userId;
        }

        public CompletableFuture<User> getCompletableFuture() {
            return completableFuture;
        }

        public void setCompletableFuture(CompletableFuture<User> completableFuture) {
            this.completableFuture = completableFuture;
        }

        public Request() {
        }

        public Request(String requestId, Integer userId, CompletableFuture<User> completableFuture) {
            this.requestId = requestId;
            this.userId = userId;
            this.completableFuture = completableFuture;
        }

        @Override
        public String toString() {
            return "Request{" +
                    "requestId='" + requestId + '\'' +
                    ", userId=" + userId +
                    ", completableFuture=" + completableFuture +
                    '}';
        }

    }




    //用户存储请求对象
    private final Queue<Request> queue =new LinkedBlockingQueue<>();


    @PostConstruct
    public void init(){
        //定时任务线程池，创建一个支持定时、周期性或延时任务的限定线程数目（这里传入的是1）的线程池
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);


        scheduledExecutorService.scheduleAtFixedRate(()->{

            int size = queue.size();
            //如果队列没数据，表示这段时间没有请求，直接返回
            if (size==0){
                return;
            }
            ArrayList<Request> list = new ArrayList<>();
            System.out.println("合并了 ["+size+"] 个请求");

            //将队列的请求消费保存到一个集合保存
            for (int i = 0; i < size; i++) {
                //后面的sql语句是有长度限制的，所以还要做现职每次批量的数量

                if (i<MAX_TASK_NUM){
                    list.add(queue.poll());
                }
            }

            //拿到我们需要去数据库查询的特征，保存为集合
            ArrayList<Request> userReqs = new ArrayList<>();

            for (Request request : list) {
                userReqs.add(request);
            };
            //将参数传入service处理，这里是本地服务，也可以把userService，看成RPC之类的远程调用
            Map<String, User> response =  userService.queryUserByIdBatch(userReqs);
            //将处理结果返回各自的请求
            for (Request request : list) {

                User result  = response.get(request.requestId);
                request.completableFuture.complete(result);  //completableFuture.complete方法完成赋值这一步
            }



        },1000,50, TimeUnit.MILLISECONDS);
        //scheduleAtFixedRate是周期性执行 schedule是延迟执行 initialDelay是初始延迟 period是周期间隔 后面是单位
        //这里我写的是 初始化后1000毫秒后执行，周期性执行50毫秒执行一次




    }


    public User queryUser(Integer userId) {
        Request  request = new Request();
        // 这里用UUID做请求id
        request.requestId = UUID.randomUUID().toString().replace("-", "");
        request.userId = userId;
        CompletableFuture<User> future = new CompletableFuture<>();
        request.completableFuture = future;
        //将对象传入队列
        queue.offer(request);
        //如果这时候没完成赋值,那么就会阻塞,直到能够拿到值
        try {
            return future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return null;
    }
}
